<!--
 * @Author: '周云芳‘ '164591357@qq.com'
 * @Date: 2022-08-14 13:33:53
 * @LastEditors: 周云芳 164591357@qq.com
 * @LastEditTime: 2022-08-15 09:29:35
 * @FilePath: \canvas-flowers\flower.html
 * @Description: 花卉特效
-->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>花卉特效2.0版本</title>
    <style>
        body,
        html {
            padding: 0;
            margin: 0;

        }

        canvas {
            background-color: #ddd;
            width: 100%;
            height: 100%;

        }
    </style>
</head>

<body>
    <canvas></canvas>
    <script>
        let canvas = {
            // 初始化canvas
            init () {
                let oC = document.querySelector('canvas');
                this.ele = oC
                this.resize()
                window.addEventListener('resize', () => {
                    this.resize()
                })
                let cxt = oC.getContext('2d')
                return cxt
            },
            // 改变窗口大小的时候让canvas自适应
            resize () {
                this.ele.width = window.innerWidth
                this.ele.height = window.innerHeight
            }
        }
        let cxt = canvas.init()
        let flowerArray = []
        // 创建一个花卉的类
        class Flower {
            constructor() {
                this.x = 0
                this.y = 0
                this.angle = 0//角度
                this.dAngle = Math.random()//设置参数的系数用于决定圈的大小
                this.radius = Math.random() * 20 + 5//设置半径最小为5
                this.stop = false//停止画花卉的标识
                this.leftOrRight = Math.random() < 0.5//设置一个随机的顺时针或逆时针
                this.color = `hsl(${Math.floor(Math.random() * 360)},70%,60%)`//一个彩色的样式360度的一个随机整数，70%百分比和60%的高度
            }
            // 坐标通过鼠标事件得到的，通过事件来设置坐标及角度
            reset (x, y, angle) {
                this.x = x
                this.y = y
                this.angle = angle
                this.leftOrRight = Math.random() < 0.5//设置一个随机的顺时针或逆时针,,返回Boolean值
                this.dAngle = Math.random()//设置参数的系数用于决定圈的大小
            }
            // 画花卉
            draw (cxt) {
                if (this.stop) return
                // cos 方法返回一个 -1 到 1 之间的数值，表示角度（单位：弧度）的余弦值。
                this.x += Math.cos(this.angle) * this.radius//每次调用时画就会以radius的半径延伸再画一个
                // sin 方法返回一个 -1 到 1 之间的数值，表示给定角度（单位：弧度）的正弦值。
                this.y += Math.sin(this.angle) * this.radius  //每次调用时画就会以radius的半径Y轴延伸再画一个
                cxt.beginPath()
                // 设置七色
                cxt.fillStyle = this.color
                cxt.arc(this.x, this.y, this.radius * 0.5, 0, 2 * Math.PI)// * 0.5防止重叠
                cxt.stroke()//默认黑色边框
                cxt.fill()//颜色填充
                if (this.leftOrRight) {//顺时针
                    this.angle += this.dAngle//随机大小赋值给角度 
                } else {
                    this.angle -= this.dAngle
                }
                // 越画越小当小于0的时候就停止画
                this.radius -= 0.4
                if (this.radius <= 0) {
                    this.stop = true
                }
            }
        }
        // 因画的位置坐标和鼠标相关在这里定义一些和鼠标相当的参数
        let pointer = {
            x: 0,
            y: 0,
            oldX: 0,
            oldY: 0,
            layout: 0,//用于阴影
            init () {
                canvas.ele.addEventListener('mousemove', (e) => {
                    this.move(e.clientX, e.clientY)
                })
            },
            move (x, y) {
                let f = new Flower()
                /**
                 * Math.atan2 这是一个逆时针角度,计算角度
                 * 函数接受的参数：先传递 y 坐标，然后是 x 坐标，注意：它是一个点的坐标
                 * 返回的的是一个逆时针旋转的弧度值
                 *  角度=弧度*180/Math.PI
                 * 45°=Math.atan2(5,5)/ (Math.PI/180)(atan2(5,5) 就是 arctan(5/5)tan45°==1)
                 *  返回从原点 (0,0) 到 (x,y) 点的线段与 x 轴正方向之间的平面角度 (弧度值)
                 * 
                 * */
                let angle = Math.atan2(y - this.oldY, x - this.oldX)//返回y,x之间的角度
                f.reset(x, y, angle)//计算角度
                flowerArray.push(f)
                if (flowerArray.length > 200) {//设置最大数量,防止无止尽
                    flowerArray.shift()
                }
                // 计算方向
                this.oldX = x
                this.oldY = y
                this.layout++
                if (this.layout % 3 == 0) {
                    // 当属于层是3的倍数后就画个阴影
                    cxt.fillStyle = 'rgba(8,8,8,0.05)';
                    cxt.fillRect(0, 0, canvas.ele.width, canvas.ele.height)
                }
            }

        }
        function play () {
            // 画出不同颜色的效果
            for (let i = 0; i < flowerArray.length; i++) {//鼠标移入的时候会把数据推入数组中,然后根据数组中的
                const f = flowerArray[i];
                f.draw(cxt)// 调用画花卉方法
            }
            window.requestAnimationFrame(play)
        }
        pointer.init()//触发鼠标移入事件
        play()
    </script>

</body>

</html>